package Baterias;

import java.util.ArrayList;
import Utilidades.HTML_Parser;

/**
 * @brief: Esta Clase es la representacion abstracta del recurso gestionado por
 *         el monitor. Contiene los metodos que se ejecutan sobre la matriz de
 *         incidencia de la red de petri. En principio, esta clase esta
 *         TERMINADA
 * @author Marcelo
 * @version 1.0
 */
public class Petri {
	// Campos de la clase Petri
	private int[][] matrizDeIncidencia; // matriz[filas][columnas]
	private int[][] marcacionActual; // una columna nomas
	private ArrayList<int[][]> VectoresDeDisparo;
	private ArrayList<int[][]> VectoresRestart;
	private final String path = "./Archivos PetriNet/MatrizNueva.html";
	
	/**
	 * @brief Constructor predeterminado de la clase Petri
	 */
	public Petri() {
		leerMatrizDeIncidencia();
		inicializarMarcacion();
		inicializarVectoresDeDisparoYRestart();
	}

	/**
	 * @brief Este metodo deberia leer el archivo salido del Pipe con la matriz
	 *        y la carga en un campo de la clase
	 */
	private void leerMatrizDeIncidencia() {
		// matrizDeIncidencia = new int[9][16]; //9Plazas-16Transiciones
		HTML_Parser parser = new HTML_Parser(path);
		parser.leerHTML();
		int[][] nuevaMatriz = parser.getMatriz();
		matrizDeIncidencia = nuevaMatriz;
	}

	/**
	 * @brief Este metodo muestra la matriz de insidencia leida
	 */
	public void printMatriz() {
		System.out.println("Matriz de Incidencia:");
		printVector(matrizDeIncidencia);
	}

	/**
	 * @brief Metodo que imprime el vector de marcacion actual.
	 */
	public void printMarcacion() {
		printVector(marcacionActual);
	}

	/**
	 * @brief Metodo que imprime un vector bidimensional que se le pase como
	 *        parametro
	 * @param vector
	 */
	public void printVector(int[][] vector) {
		System.out.println("Dimensiones: [" + vector.length + "x"
				+ vector[0].length + "]");
		for (int i = 0; i < vector.length; i++) {
			for (int j = 0; j < vector[0].length; j++) {
				if (vector[i][j] == -1)
					System.out.print(" " + vector[i][j]);
				else
					System.out.print("  " + vector[i][j]);
			}
			System.out.print("\n");
		}

	}

	/**
	 * @brief: Metodo que inicializa el campo marcacionActual en un valor
	 *         determinado
	 */
	private void inicializarMarcacion() {
		// int[][] marcacionInicial = {{4},{0},{0},{0},{0},{0},{0},{0},{0}};
		// //vieja
		int[][] marcacionInicial = { { 4 }, { 0 }, { 0 }, { 0 }, { 0 }, { 1 },
				{ 1 }, { 1 }, { 1 } }; // Nueva
		marcacionActual = marcacionInicial;
	}

	/**
	 * @brief Funcion que inicializa los valores de los vectores que representan
	 *        los disparos de las baterias en la red e petri, tanto los
	 *        iniciales como los restart.
	 */
	private void inicializarVectoresDeDisparoYRestart() {
		// Vectores de Disparo
		VectoresDeDisparo = new ArrayList<int[][]>();
		/*
		 * Vectores Viejos int[][] vectorNorte1 =
		 * {{1},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}};
		 * int[][] vectorSur2 =
		 * {{0},{1},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}};
		 * int[][] vectorEste3 =
		 * {{0},{0},{1},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}};
		 * int[][] vectorOeste4 =
		 * {{0},{0},{0},{1},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}};
		 */
		// Vectores Nuevos
		int[][] vectorNorte1 = { { 1 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
				{ 0 }, { 0 } };
		int[][] vectorSur2 = { { 0 }, { 1 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
				{ 0 } };
		int[][] vectorEste3 = { { 0 }, { 0 }, { 1 }, { 0 }, { 0 }, { 0 },
				{ 0 }, { 0 } };
		int[][] vectorOeste4 = { { 0 }, { 0 }, { 0 }, { 1 }, { 0 }, { 0 },
				{ 0 }, { 0 } };

		VectoresDeDisparo.add(vectorNorte1);
		VectoresDeDisparo.add(vectorSur2);
		VectoresDeDisparo.add(vectorEste3);
		VectoresDeDisparo.add(vectorOeste4);

		// Vectores de Restart
		VectoresRestart = new ArrayList<int[][]>();
		/*
		 * VECTORES VIEJOS int[][] restartNorte11 =
		 * {{0},{0},{0},{0},{1},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}};
		 * int[][] restartSur21 =
		 * {{0},{0},{0},{0},{0},{1},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}};
		 * int[][] restartEste31 =
		 * {{0},{0},{0},{0},{0},{0},{1},{0},{0},{0},{0},{0},{0},{0},{0},{0}};
		 * int[][] restartOeste41 =
		 * {{0},{0},{0},{0},{0},{0},{0},{1},{0},{0},{0},{0},{0},{0},{0},{0}};
		 * int[][] restartNorte12 =
		 * {{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{1},{0},{0},{0}};
		 * int[][] restartSur22 =
		 * {{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{1},{0},{0}};
		 * int[][] restartEste32 =
		 * {{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{1},{0}};
		 * int[][] restartOeste42 =
		 * {{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{1}};
		 * VectoresRestart.add(restartNorte11);
		 * VectoresRestart.add(restartSur21);
		 * VectoresRestart.add(restartEste31);
		 * VectoresRestart.add(restartOeste41);
		 * VectoresRestart.add(restartNorte12);
		 * VectoresRestart.add(restartSur22);
		 * VectoresRestart.add(restartEste32);
		 * VectoresRestart.add(restartOeste42);
		 */
		// Vectores nuevos
		int[][] restartNorte1 = { { 0 }, { 0 }, { 0 }, { 0 }, { 1 }, { 0 },
				{ 0 }, { 0 } };
		int[][] restartSur2 = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 1 },
				{ 0 }, { 0 } };
		int[][] restartEste3 = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
				{ 1 }, { 0 } };
		int[][] restartOeste4 = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
				{ 0 }, { 1 } };
		VectoresRestart.add(restartNorte1);
		VectoresRestart.add(restartSur2);
		VectoresRestart.add(restartEste3);
		VectoresRestart.add(restartOeste4);
	}

	/**
	 * @brief Funcion que devuelve el vector de disparo correspondiente al
	 *        indice de una bateria determinada.
	 * @param indice
	 * @return vector de disparo
	 */
	public int[][] getVectorDeDisparo(int indice) {

		return VectoresDeDisparo.get(indice);
	}

	/**
	 * @brief Funcion que devuelve el vector de restart correspondiente al
	 *        indice de una bateria determinada.
	 * @param indice
	 * @return vector de restart
	 */
	public int[][] getVectorRestart(int indice) {
		return VectoresRestart.get(indice);
	}

	/**
	 * @brief Este metodo efectua un disparo dado un vector de disparo. requiere
	 *        la matriz de incidencia y la marcacion actual.
	 * @param vectorDeDisparo
	 *            : Compuesto de unos y ceros, solo puede contener un unico
	 *            valor distinto de cero.
	 * @return verdadero si se puede efectuar el disparo (resultado sin numeros
	 *         negativos) falso si no se puede efectuar el disparo (resultado
	 *         con uno o mas numeros negativos)
	 */
	public boolean dispararTransicion(int[][] vectorDeDisparo) {
		if (vectorDeDisparo.length != matrizDeIncidencia[0].length) {
			System.err
					.println("ERROR en Metodo efectuarDisparo(): Error en la Dimension de los Operandos");
			System.out.println("Vector: " + vectorDeDisparo.length
					+ "x1  Matriz: 9x" + matrizDeIncidencia[0].length);
			return false;
		}

		int[][] nuevaMarcacion = new int[marcacionActual.length][marcacionActual[0].length];
		// nuevaMarcacion=marcacionActual+matrizDeIncidencia*vectorDeDisparo;

		int columna = -1; // Numero de fila no nula del vectorDeDisparo (columna
							// a elegir dela matriz)
		for (int i = 0; i < vectorDeDisparo.length; i++) {
			if (vectorDeDisparo[i][0] == 1) {
				columna = i;
			}
		}

		// Si el disparo es no disparar nada, se puede hacer
		if (columna == -1) {
			return true;
		}
		// Hacer el Mi+1=Mi+A*d propiamente dicho
		for (int i = 0; i < marcacionActual.length; i++) {
			nuevaMarcacion[i][0] = marcacionActual[i][0]
					+ matrizDeIncidencia[i][columna];
		}
		// printVector(nuevaMarcacion);
		if (buscarNegativos(nuevaMarcacion)) {// Si hay negativos
			return false;
		} else {// Si no hay negativos => el disparo se puede efectuar
			marcacionActual = nuevaMarcacion;
			return true;
		}

	}

	/**
	 * @brief Metodo que busca la presencia de valores negativos en el vector
	 *        que se le pasa com parametro
	 * @param nuevaMarcacion
	 * @return true si hay negativos, false si no los hay
	 */
	private boolean buscarNegativos(int[][] nuevaMarcacion) {
		boolean tieneNegativos = false;
		for (int i = 0; i < nuevaMarcacion.length; i++) {
			// System.out.println(nuevaMarcacion[i][0]);
			if (nuevaMarcacion[i][0] < 0) {
				tieneNegativos = true;
			}
		}
		return tieneNegativos;
	}

	/**
	 * @brief Metodo que verifica si determinada bateria esta o no disponible.
	 *        Este metodo es especifico de la red de petri nueva
	 * @param indice
	 * @return
	 */
	public boolean[] checkDisponibles() {
		boolean[] disponibles = new boolean[4];
		disponibles[0]=marcacionActual[1+0][0]==0;
		disponibles[1]=marcacionActual[1+1][0]==0;
		disponibles[2]=marcacionActual[1+2][0]==0;
		disponibles[3]=marcacionActual[1+3][0]==0;
		
		return disponibles;
	}

}
